/**
 * 专业级深拷贝函数
 * @param {any} target - 需要克隆的目标对象
 * @param {WeakMap} [cache] - 用于处理循环引用的缓存
 * @returns {any} - 完整克隆后的新对象
 */

function deepClone (target, cache = new WeakMap()) {
  // 处理 null 和 undefined
  if (target === null || target === undefined) return target;

  // 处理基本数据类型和Symbol
  if (typeof target !== 'object') return target;

  // 处理循环引用
  if (cache.has(target)) return cache.get(target);

  // 获取目标类型
  const targetType = Object.prototype.toString.call(target);
  let clone;

  switch (targetType) {
    case '[object Array]':
      clone = [];
      target.forEach(item => clone.push(deepClone(item, cache)));
      break;

    case '[object Object]':
      clone = {};
      const keys = Reflect.ownKeys(target);
      keys.forEach(key => {
        clone[key] = deepClone(target[key], cache);
      });
      break;

    case '[object Date]':
      clone = new Date(target.getTime());
      break;

    case '[object RegExp]':
      clone = new RegExp(target);
      break;

    case '[object Map]':
      clone = new Map();
      target.forEach((value, key) => {
        clone.set(deepClone(key, cache), deepClone(value, cache));
      });
      break;

    case '[object Set]':
      clone = new Set();
      target.forEach(item => clone.add(deepClone(item, cache)));
      break;

    case '[object ArrayBuffer]':
      clone = target.slice(0);
      break;

    case '[object DataView]':
      clone = new DataView(target.buffer, target.byteOffset, target.byteLength);
      break;

    default:
      // 处理自定义对象和类实例
      clone = Object.create(Object.getPrototypeOf(target));
      Object.assign(clone, deepClone(target, cache));
      break;
  }

  // 记录循环引用
  cache.set(target, clone);
  return clone;
}

// 复杂对象克隆
const original = {
  name: 'Alice',
  age: 30,
  address: {
    city: 'Beijing',
    coordinates: [116.40, 39.90]
  },
  hobbies: new Set(['reading', 'coding']),
  meta: new Date()
};

const cloned = deepClone(original);

// 修改克隆对象
cloned.address.city = 'Shanghai';
cloned.hobbies.add('travel');
cloned.meta.setHours(cloned.meta.getHours() + 1);

console.log(original.address.city); // Beijing（原对象未变）
console.log(cloned.meta); // 原日期+1小时